﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lails.Config
{
    /// <summary>
    /// 配置文件加载器
    /// </summary>
    public class ConfigLoader
    {
        /// <summary>
        /// 加载配置文件，从地址中自动识别是加载文件还是Url
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path">配置文件的路径或Url地址</param>
        /// <returns></returns>
        public static T Load<T>(string path)
        {
            if (path.StartsWith("http://") || path.StartsWith("https://"))  //远程地址
            {
                return LoadFromUrl<T>(path);
            }
            else  //本地文件
            {
                return LoadFromFile<T>(path);
            }
        }

        /// <summary>
        /// 从Url地址中加载配置文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <returns></returns>
        private static T LoadFromUrl<T>(string url)
        {
            T curConfig = default(T), parentConfig = default(T);
            var curJson = DownLoad(url);
            if (!string.IsNullOrEmpty(curJson))
            {
                curConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(curJson);
            }

            var uri = new Uri(url);
            string parentPath = "";
            for (int i = 0; i < uri.Segments.Length - 2; i++)
            {
                parentPath += uri.Segments[i];
            }
            parentPath += uri.Segments.Last();
            var parentUrl = $"{uri.Scheme}://{uri.Host}/{parentPath}";
            var parentJson = DownLoad(parentUrl);
            if (!string.IsNullOrEmpty(parentJson))
            {
                parentConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(parentJson);
            }

            return JoinConfig<T>(curConfig, parentConfig);
        }

        private static string DownLoad(string url)
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            var taskRequest = client.GetAsync(url);
            var req = taskRequest.Result;
            var taskResponse = req.Content.ReadAsStringAsync();
            if (req.StatusCode == System.Net.HttpStatusCode.OK) //当前Url未找到该配置文件
            {
                var repJson = taskResponse.Result;
                return repJson;
            }

            return null;
        }
        /// <summary>
        /// 从文件中加载配置文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filename">配置文件路径</param>
        /// <returns></returns>
        private static T LoadFromFile<T>(string filename)
        {
            string curDir = AppDomain.CurrentDomain.BaseDirectory;
            string curPath =  Path.Combine(curDir, filename);
            T curConfig = default(T), parentConfig = default(T);
            if (File.Exists(curPath))
            {
                string jsonConfig = File.ReadAllText(curPath);
                curConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonConfig);
            }
            var dirInfo = new DirectoryInfo(curDir);

            string parentDir = dirInfo.Parent.FullName;
            string parentPath = Path.Combine(parentDir, filename);
            if (File.Exists(parentPath))
            {
                string jsonConfig = File.ReadAllText(parentPath);
                parentConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonConfig);
            }

            return JoinConfig<T>(curConfig, parentConfig);
        }

        //合并配置文件
        private static T JoinConfig<T>(T cur, T parent)
        {
            if (cur == null)
            {
                return default(T);
            }
            if (parent == null)
            {
                return cur;
            }

            foreach (var pro in typeof(T).GetProperties())
            {
                var curValue = pro.GetValue(cur);
                if (curValue == null) //当前未配置的项，从上级配置文件中读取
                {
                    var parentValue = pro.GetValue(parent);
                    pro.SetValue(pro, parentValue);
                }
            }
            return cur;
        }

        /// <summary>
        /// 保存配置文件
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static void SaveConfig<T>(T config, string filename)
        {
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(config);
            if (File.Exists(filename))
            {
                File.Delete(filename);
            }
            using (var fs = File.CreateText(filename))
            {
                fs.WriteLine(json);
            }
        }
    }
}
